/**
 * Created by gaoyinxin on 2/12/15.
 */

var DIRECTION = {
    LEFT: 0,
    RIGHT: 1,
    UP: 2,
    DOWN: 3
};

var GameBoard = cc.Class.extend({
    _cards: new Array(),
    _snapshot: new Array(),
    _frozen: false,
    _layer: null,
    /* dimension */
    _D: 4,
    /* position of board */
    _boardX: 0,
    _boardY: 0,
    _boardW: 0,
    /* layout of tablets */
    _space: 0,
    _tabletSize: 0,
    ctor: function (layer, left, top, width) {
        this._layer = layer;
        this._boardX = left;
        this._boardY = top;
        this._boardW = width;
        this._initBg();
        this._initCards();
        this._born(true);
    },
    _initBg: function () {
        this._space = this._boardW / (8 * this._D + 1);
        this._tabletSize = this._space * 7;
        var bg = new cc.LayerColor(cc.color(186, 174, 161));
        bg.setPosition(cc.p(this._boardX, this._boardY - this._boardW));
        bg.setContentSize(this._boardW, this._boardW);
        this._layer.addChild(bg, 1);
    },
    _initCards: function () {
        for (var i = 0; i < this._D; i++) { //column
            this._cards[i] = new Array();
            for (var j = 0; j < this._D; j++) { //row
                var left = this._space * (j + 1) + this._tabletSize * j + this._boardX;
                var top = this._boardY - this._space * (i + 1) - this._tabletSize * (i + 1);
                // card is layer type. the anchor is at (0,0)
                // so the top shall reduced by its height.
                var bgTablet = new Card(left, top, this._tabletSize);
                this._layer.addChild(bgTablet, 5);
                this._cards[i][j] = bgTablet;
            }
        }
        this._saveBoard();
    },
    _born: function (force) {
        if (!force) force = false;
        if (!force && !this._isChanged()) return;
        var slot = this._searchEmptySlot();
        if (slot == null) return;
        var i = slot.shift();
        var j = slot.shift();
        var card = this._cards[i][j];
        var values = [2, 4];
        //var values = [2, 4, 8, 1024, 2048, 4096];
        var value = values[Math.floor(Math.random() * values.length)];
        card.born();
        card.setValue(value);
        this._layer.addScore(value);
    },
    _searchEmptySlot: function () {
        var slots = new Array();
        for (var i = 0; i < this._D; i++) { //column
            for (var j = 0; j < this._D; j++) { //row
                if (this._cards[i][j].isEmpty())
                    slots.push([i, j]);
            }
        }
        if (slots.length == 0) return null;
        else return slots[Math.floor(Math.random() * slots.length)];
    },
    _getNext: function (act, i, j) {
        var result = null;
        var current = this._cards[i][j];
        switch (act) {
            case DIRECTION.LEFT:
                if (j == 0) return result;
                for (var n = j - 1; n >= 0; n--) {
                    var target = this._cards[i][n];
                    if (target.isFrozen() == false &&
                        (target.isEmpty() || current.equal(target)))
                        result = target;
                    else break;
                }
                break;
            case DIRECTION.RIGHT:
                if (j == this._D - 1) return result;
                for (var n = j + 1; n < this._D; n++) {
                    var target = this._cards[i][n];
                    if (target.isFrozen() == false &&
                        (target.isEmpty() || current.equal(target)))
                        result = target;
                    else break;
                }
                break;
            case DIRECTION.UP:
                if (i == 0) return result;
                for (var n = i - 1; n >= 0; n--) {
                    var target = this._cards[n][j];
                    if (target.isFrozen() == false &&
                        (target.isEmpty() || current.equal(target)))
                        result = target;
                    else break;
                }
                break;
            case DIRECTION.DOWN:
                if (i == this._D - 1) return result;
                for (var n = i + 1; n < this._D; n++) {
                    var target = this._cards[n][j];
                    if (target == undefined)
                        alert(n + ' ' + j);
                    if (target.isFrozen() == false &&
                        (target.isEmpty() || current.equal(target)))
                        result = target;
                    else break;
                }
                break;
            default:
                break;
        }
        return result;
    },
    _moveLeft: function () {
        for (var i = 0; i < this._D; i++) { //row
            for (var j = 1; j < this._D; j++) { //column
                var current = this._cards[i][j];
                if (current.isEmpty() == false) {
                    var slot = this._getNext(DIRECTION.LEFT, i, j);
                    if (slot == null) continue;
                    this._squeeze(current, slot);
                }
            }
        }
    },
    _moveRight: function () {
        for (var i = 0; i < this._D; i++) { //row
            for (var j = this._D - 1; j >= 0; j--) { //column
                var current = this._cards[i][j];
                if (current.isEmpty() == false) {
                    var slot = this._getNext(DIRECTION.RIGHT, i, j);
                    if (slot == null) continue;
                    this._squeeze(current, slot);
                }
            }
        }
    },
    _moveUp: function () {
        for (var j = 0; j < this._D; j++) { //column
            for (var i = 1; i < this._D; i++) { //row
                var current = this._cards[i][j];
                if (current.isEmpty() == false) {
                    var slot = this._getNext(DIRECTION.UP, i, j);
                    if (slot == null) continue;
                    this._squeeze(current, slot);
                }
            }
        }
    },
    _moveDown: function () {
        for (var j = 0; j < this._D; j++) { //column
            for (var i = this._D - 1; i >= 0; i--) { //row
                var current = this._cards[i][j];
                if (current.isEmpty() == false) {
                    var slot = this._getNext(DIRECTION.DOWN, i, j);
                    if (slot == null) continue;
                    this._squeeze(current, slot);
                }
            }
        }
    },
    _squeeze: function (current, target) {
        if (target.isEmpty()) {
            current.ghostMove(target);
            var value = current.getValue();
            current.clear();
            target.setValue(value);
        } else if (current.equal(target)) {
            if (!target.isFrozen()) {
                current.ghostMove(target);
                current.clear();
                target.double();
                target.bloat();
                if (target.getValue() >= 1024)
                    target.spark();
                target.setFrozen(true);
            }
        }
    },
    _unfreezeAllCards: function () {
        for (var i = 0; i < this._D; i++) { //row
            for (var j = 0; j < this._D; j++) { //column
                this._cards[i][j].setFrozen(false);
            }
        }
    },
    _saveBoard: function () {
        this._snapshot.length = 0;
        for (var i = 0; i < this._D; i++) { //row
            this._snapshot[i] = new Array();
            for (var j = 0; j < this._D; j++) { //column
                this._snapshot[i][j] = this._cards[i][j].getValue();
            }
        }
    },
    _isChanged: function () {
        for (var i = 0; i < this._D; i++) { //column
            for (var j = 0; j < this._D; j++) { //row
                if (this._snapshot[i][j] != this._cards[i][j].getValue())
                    return true;
            }
        }
        return false;
    },
    judge: function () {
        var result = false;
        for (var i = 0; i < this._D; i++) { //row
            for (var j = 0; j < this._D; j++) { //column
                if (this._getNext(DIRECTION.LEFT, i, j) != null ||
                    this._getNext(DIRECTION.RIGHT, i, j) != null ||
                    this._getNext(DIRECTION.UP, i, j) != null ||
                    this._getNext(DIRECTION.DOWN, i, j) != null) {
                    result = true;
                    return result;
                }
            }
        }
        return result;
    },
    move: function (act) {
        this._saveBoard();
        switch (act) {
            case DIRECTION.LEFT:
                this._moveLeft();
                break;
            case DIRECTION.RIGHT:
                this._moveRight();
                break;
            case DIRECTION.UP:
                this._moveUp();
                break;
            case DIRECTION.DOWN:
                this._moveDown();
                break;
            default:
                break;
        }
        this._unfreezeAllCards();
        this._born();
    },
    isFrozen: function () {
        return this._frozen;
    },
    setFrozen: function (b) {
        this._frozen = b;
    }
});